package com.liaoyifan.core.valid;

import com.liaoyifan.core.util.Try;
import jakarta.validation.ConstraintValidatorContext;
import java.nio.charset.StandardCharsets;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;

@SuppressWarnings("unused")
@Log4j2
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class Message {

    public static final MessageSource MESSAGE_SOURCE = messageSource();

    private static final Pattern PATTERN = Pattern.compile("\\{([^}]+)}");

    private static final Map<String, String> TEMPLATE_CACHE = new ConcurrentHashMap<>(1024);

    public static String get(String message) {
        return get(message, null);
    }

    public static String get(String message, Map<String, Object> args) {
        return get(message, args, LocaleContextHolder.getLocale());
    }

    public static String get(String message, Map<String, Object> args, Locale locale) {
        if (!PATTERN.matcher(message).find()) {
            return message;
        }
        String messageKey = message.replaceAll("[{}]", "");
        // 从缓存获取模板，未命中则从MessageSource获取并缓存
        String template =
                TEMPLATE_CACHE.computeIfAbsent(
                        messageKey + "_" + locale,
                        k -> MESSAGE_SOURCE.getMessage(messageKey, null, locale));
        if (args == null || args.isEmpty() || !PATTERN.matcher(template).find()) {
            return template;
        }
        Object[] positionalArgs = new Object[args.size()];
        return MessageFormat.format(replace(template, args, positionalArgs), positionalArgs);
    }

    @SuppressWarnings("SameReturnValue")
    public static boolean build(String message, ConstraintValidatorContext context) {
        context.disableDefaultConstraintViolation();
        context.buildConstraintViolationWithTemplate(message).addConstraintViolation();
        return false;
    }

    private static String replace(
            String template, Map<String, Object> args, Object[] positionalArgs) {
        StringBuilder result = new StringBuilder();
        Matcher matcher = PATTERN.matcher(template);
        int index = 0;
        while (matcher.find()) {
            String paramName = matcher.group(1); // 获取参数名，如 "name"

            if (args.containsKey(paramName)) {
                // 保存参数值到位置参数数组
                positionalArgs[index] = args.get(paramName);
                // 替换为位置占位符 {0}, {1}, ...
                matcher.appendReplacement(result, "{" + index + "}");
                index++;
            } else {
                // 参数不存在，保持原样
                matcher.appendReplacement(result, matcher.group(0));
            }
        }
        matcher.appendTail(result);
        return result.toString();
    }

    private static MessageSource messageSource() {
        ReloadableResourceBundleMessageSource source = new ReloadableResourceBundleMessageSource();
        Set<String> baseNames =
                Try.run(
                                () ->
                                        Arrays.stream(
                                                new PathMatchingResourcePatternResolver()
                                                        .getResources(
                                                                ResourcePatternResolver
                                                                                .CLASSPATH_ALL_URL_PREFIX
                                                                        + "/i18n/**/*.properties")))
                        .map(
                                resource ->
                                        Try.run(
                                                () -> {
                                                    String uri = resource.getURI().toString();
                                                    String path =
                                                            uri.substring(uri.indexOf("i18n/"));
                                                    path =
                                                            path.substring(
                                                                    0,
                                                                    path.lastIndexOf('.')); // 移除扩展名
                                                    return path.replaceFirst(
                                                                    "(_[a-z]{2}(_[A-Z]{2})?)$", "")
                                                            .replace("\\", "/");
                                                }))
                        .filter(Objects::nonNull)
                        .collect(Collectors.toSet());
        log.info("MessageSource baseNames: {}", baseNames);
        source.setBasenames(
                baseNames.stream()
                        .map(i -> ResourcePatternResolver.CLASSPATH_URL_PREFIX + i)
                        .toArray(String[]::new));
        source.setDefaultEncoding(StandardCharsets.UTF_8.name());
        Locale.setDefault(Locale.SIMPLIFIED_CHINESE);
        return source;
    }
}
